package com.scheduling.schedule.factory;

import cn.hutool.core.collection.CollUtil;
import com.scheduling.product.entity.Operation;
import com.scheduling.schedule.entity.ProductionTask;
import com.scheduling.schedule.entity.WorkOrder;
import com.scheduling.schedule.service.OperationScheduleService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 生产任务工厂
 * 基于真实的工艺路线创建生产任务
 *
 * @author 开发团队
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ProductionTaskFactory {

    private final OperationScheduleService operationScheduleService;

    /**
     * 为工单创建基于工艺路线的生产任务
     *
     * @param workOrder       工单
     * @param taskSequence    任务序号生成器
     * @param algorithmPrefix 算法前缀
     * @return 生产任务列表
     */
    public List<ProductionTask> createTasksForWorkOrder(WorkOrder workOrder,
                                                        AtomicInteger taskSequence,
                                                        String algorithmPrefix) {
        log.debug("为工单 {} 创建基于工艺路线的生产任务", workOrder.getWorkOrderId());

        List<ProductionTask> tasks = new ArrayList<>();

        // 1. 获取产品的工艺路线
        List<Operation> operations = operationScheduleService.getOperationsByProductId(workOrder.getProductId());

        if (CollUtil.isEmpty(operations)) {
            log.warn("产品 {} 没有配置工艺路线，使用默认工序", workOrder.getProductId());
            // 创建默认任务
            ProductionTask defaultTask = createDefaultTask(workOrder, taskSequence, algorithmPrefix);
            tasks.add(defaultTask);
            return tasks;
        }

        log.debug("产品 {} 有 {} 个工序", workOrder.getProductId(), operations.size());

        // 2. 为每个工序创建生产任务
        for (Operation operation : operations) {
            ProductionTask task = createTaskForOperation(workOrder, operation, taskSequence, algorithmPrefix);
            tasks.add(task);
        }

        return tasks;
    }

    /**
     * 为单个工序创建生产任务
     */
    private ProductionTask createTaskForOperation(WorkOrder workOrder,
                                                  Operation operation,
                                                  AtomicInteger taskSequence,
                                                  String algorithmPrefix) {
        ProductionTask task = new ProductionTask();

        // 生成任务ID
        String taskId = String.format("%s_%s_%s_%06d",
                algorithmPrefix,
                workOrder.getProductId(),
                operation.getOperationCode(),
                taskSequence.getAndIncrement());
        task.setTaskId(taskId);

        // 设置基本信息
        task.setWorkOrderId(workOrder.getWorkOrderId());
        task.setOperationId(operation.getOperationId());
        task.setQuantity(workOrder.getQuantity());
        task.setStatus("待分配");

        // 设置时间信息
        task.setStandardTime(operation.getStandardTime() * workOrder.getQuantity());
        task.setPlannedTime(operation.getStandardTime() * workOrder.getQuantity());

        // 设置创建时间
        task.setCreateTime(LocalDateTime.now());
        task.setUpdateTime(LocalDateTime.now());

        log.debug("为工序 {} 创建任务 {}, 标准时间: {}分钟",
                operation.getOperationCode(), taskId, task.getStandardTime());

        return task;
    }

    /**
     * 创建默认任务（当产品没有工艺路线时）
     */
    private ProductionTask createDefaultTask(WorkOrder workOrder,
                                             AtomicInteger taskSequence,
                                             String algorithmPrefix) {
        ProductionTask task = new ProductionTask();

        String taskId = String.format("%s_DEFAULT_%06d", algorithmPrefix, taskSequence.getAndIncrement());
        task.setTaskId(taskId);
        task.setWorkOrderId(workOrder.getWorkOrderId());
        task.setOperationId("OP001"); // 默认工序
        task.setQuantity(workOrder.getQuantity());
        task.setStatus("待分配");

        // 默认时间估算：每件产品60分钟
        int totalTime = (workOrder.getQuantity() != null ? workOrder.getQuantity() : 1) * 60;
        task.setStandardTime(totalTime);
        task.setPlannedTime(totalTime);

        task.setCreateTime(LocalDateTime.now());
        task.setUpdateTime(LocalDateTime.now());

        log.debug("为工单 {} 创建默认任务 {}", workOrder.getWorkOrderId(), taskId);

        return task;
    }

    /**
     * 分配机器给生产任务
     *
     * @param tasks                生产任务列表
     * @param machineAvailableTime 机器可用时间表
     * @param scheduleStartTime    排产开始时间
     * @return 更新后的机器可用时间表
     */
    public Map<String, LocalDateTime> assignMachinesToTasks(List<ProductionTask> tasks,
                                                            Map<String, LocalDateTime> machineAvailableTime,
                                                            LocalDateTime scheduleStartTime) {
        log.debug("开始为 {} 个任务分配机器", tasks.size());

        Map<String, LocalDateTime> updatedMachineTime = new HashMap<>(machineAvailableTime);

        for (ProductionTask task : tasks) {
            // 获取工序兼容的机器列表
            List<String> compatibleMachines = operationScheduleService.getCompatibleMachines(task.getOperationId());

            if (CollUtil.isEmpty(compatibleMachines)) {
                log.warn("工序 {} 没有可用的机器，使用默认机器", task.getOperationId());
                task.setMachineId("DEFAULT_MACHINE");
                assignTaskTime(task, scheduleStartTime, scheduleStartTime);
                continue;
            }

            // 选择最早可用的机器
            String selectedMachine = selectBestMachine(compatibleMachines, updatedMachineTime);
            task.setMachineId(selectedMachine);

            // 分配时间
            LocalDateTime taskStartTime = updatedMachineTime.getOrDefault(selectedMachine, scheduleStartTime);
            if (taskStartTime.isBefore(scheduleStartTime)) {
                taskStartTime = scheduleStartTime;
            }

            LocalDateTime taskEndTime = taskStartTime.plusMinutes(task.getPlannedTime());
            assignTaskTime(task, taskStartTime, taskEndTime);

            // 更新机器可用时间
            updatedMachineTime.put(selectedMachine, taskEndTime);

            log.debug("任务 {} 分配到机器 {}, 时间: {} - {}",
                    task.getTaskId(), selectedMachine, taskStartTime, taskEndTime);
        }

        return updatedMachineTime;
    }

    /**
     * 选择最佳机器（最早可用的机器）
     */
    private String selectBestMachine(List<String> compatibleMachines,
                                     Map<String, LocalDateTime> machineAvailableTime) {
        String bestMachine = compatibleMachines.get(0);
        LocalDateTime earliestTime = machineAvailableTime.getOrDefault(bestMachine, LocalDateTime.now());

        for (String machine : compatibleMachines) {
            LocalDateTime availableTime = machineAvailableTime.getOrDefault(machine, LocalDateTime.now());
            if (availableTime.isBefore(earliestTime)) {
                earliestTime = availableTime;
                bestMachine = machine;
            }
        }

        return bestMachine;
    }

    /**
     * 为任务分配时间
     */
    private void assignTaskTime(ProductionTask task, LocalDateTime startTime, LocalDateTime endTime) {
        task.setPlanStartTime(startTime);
        task.setPlanEndTime(endTime);
        task.setStatus("已分配");
    }

    /**
     * 处理工序依赖关系
     * 确保前置工序完成后再开始后续工序
     *
     * @param tasks 同一工单的任务列表（按工序顺序）
     */
    public void handleOperationDependencies(List<ProductionTask> tasks) {
        log.debug("处理 {} 个任务的工序依赖关系", tasks.size());

        Map<String, LocalDateTime> operationEndTimes = new HashMap<>();

        for (ProductionTask task : tasks) {
            // 检查前置工序依赖
            List<String> predecessors = operationScheduleService.getPredecessorOperations(task.getOperationId());

            if (CollUtil.isNotEmpty(predecessors)) {
                // 找到最晚的前置工序结束时间
                LocalDateTime latestPredecessorEndTime = null;
                for (String predecessor : predecessors) {
                    LocalDateTime predecessorEndTime = operationEndTimes.get(predecessor);
                    if (predecessorEndTime != null) {
                        if (latestPredecessorEndTime == null || predecessorEndTime.isAfter(latestPredecessorEndTime)) {
                            latestPredecessorEndTime = predecessorEndTime;
                        }
                    }
                }

                // 调整任务开始时间
                if (latestPredecessorEndTime != null &&
                        task.getPlanStartTime().isBefore(latestPredecessorEndTime)) {

                    LocalDateTime newStartTime = latestPredecessorEndTime;
                    LocalDateTime newEndTime = newStartTime.plusMinutes(task.getPlannedTime());

                    log.debug("任务 {} 因前置工序依赖调整时间：{} -> {}",
                            task.getTaskId(), task.getPlanStartTime(), newStartTime);

                    task.setPlanStartTime(newStartTime);
                    task.setPlanEndTime(newEndTime);
                }
            }

            // 记录当前工序的结束时间
            operationEndTimes.put(task.getOperationId(), task.getPlanEndTime());
        }
    }
} 